package com.learn.netty.nio;

import lombok.extern.slf4j.Slf4j;

import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.*;
import java.util.Iterator;
import java.util.Set;

@Slf4j
public class NIOServer {

    /**
     * 1. 创建ServerSocketChannel
     * @param args
     */
    public static void main(String[] args) throws Exception {
        // 创建服务器连接
        ServerSocketChannel serverSocketChannel = ServerSocketChannel.open();

        // 创建选择器
        Selector selector = Selector.open();

        // 监听本地6666 端口
//        serverSocketChannel.bind(new InetSocketAddress(6666));
        serverSocketChannel.socket().bind(new InetSocketAddress(6666));

        // 设置服务器连接为非阻塞方式
        serverSocketChannel.configureBlocking(false);

        // 将服务器连接注册到selector上 并绑定连接事件
        serverSocketChannel.register(selector, SelectionKey.OP_ACCEPT);

        // 循环监听
        while (true) {

            // 阻塞3s，返回事件条数，当有
            if (selector.select(3000) <= 0) {
                log.info("--无客户端连接--");
                continue;
            }

            // 选择器中有事件发生时，返回事件SelectionKey
            Set<SelectionKey> selectionKeys = selector.selectedKeys();
            Iterator<SelectionKey> keyIterator = selectionKeys.iterator();
            while (keyIterator.hasNext()) {
                // 获取selectorKey连接信息
                SelectionKey selectionKey = keyIterator.next();
                // 有客户端发起连接
                if (selectionKey.isAcceptable()) {
                    log.info("--有客户端连接--");
                    // 获取客户端channel连接, accept虽然为阻塞方式，但是由于是事件驱动，所以该接口不会造成阻塞
                    // （已经知道有请求发起连接了，直接过来拿）
                    SocketChannel socketChannel = serverSocketChannel.accept();
                    // 设置客户端连接为阻塞方式
                    socketChannel.configureBlocking(false);
                    // 将客户端连接channel注册到select进行事件监听
                    socketChannel.register(selector, SelectionKey.OP_READ, ByteBuffer.allocate(1024));
                }

                // 发送数据接收信息
                if (selectionKey.isReadable()) {
                    // 获取客户端连接的channel
                    SocketChannel socketChannel = (SocketChannel) selectionKey.channel();
                    ByteBuffer byteBuffer = (ByteBuffer) selectionKey.attachment();
                    // 将通道中的数据读入到buffer中
                    socketChannel.read(byteBuffer);
                    log.info("客户端发送消息:{}", new String(byteBuffer.array()));
                }


                keyIterator.remove();
            }
        }
    }
}
